package cc.uncarbon.module.appapi.web.app;

import cc.uncarbon.framework.core.exception.BusinessException;
import cc.uncarbon.framework.web.model.response.ApiResult;
import cc.uncarbon.module.appapi.constant.AppApiConstant;
import cc.uncarbon.module.oss.enums.UploadFileCheckResultEnum;
import cc.uncarbon.module.oss.facade.OssUploadDownloadFacade;
import cc.uncarbon.module.oss.model.request.UploadFileAttributeDTO;
import cc.uncarbon.module.oss.model.response.OssFileInfoBO;
import cc.uncarbon.module.oss.model.response.OssFileUploadResultVO;
import cc.uncarbon.module.oss.util.UploadFileChecker;
import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.DigestUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@Tag(name = "小程序-上传、接口")
@RequestMapping(value = AppApiConstant.HTTP_API_URL_PREFIX + "/api/v1")
@RequiredArgsConstructor
@RestController
@Slf4j
public class OssUploadDownloadController {
    private final OssUploadDownloadFacade ossUploadDownloadFacade;

    @Operation(summary = "上传文件", tags = "")
    @PostMapping(value = "/oss/files")

    public ApiResult<OssFileUploadResultVO> upload(@RequestPart MultipartFile file, @RequestPart(required = false) @Valid UploadFileAttributeDTO attr,
                                                   HttpServletRequest request
    ) throws IOException {
        UploadFileCheckResultEnum checkResult = UploadFileChecker.check(file,
                // 默认只能上传1024MB之内的文件，且约束后缀名
                UploadFileChecker.FILE_SIZE_1MB * 2048,
                new String[]{"jpg", "png", "webp", "gif", "xlsx","jpeg"});
        if (checkResult.isNotOK()) {
            throw new BusinessException(checkResult.getLabel());
        }
              /*
        1. 已存在相同 MD5 文件，直接返回 URL
         */
        String md5 = DigestUtil.md5Hex(file.getBytes());
        OssFileInfoBO bo = ossUploadDownloadFacade.findByHash(md5);
        if (bo == null) {

            /*
            2. 普通上传
             */
            attr = ObjectUtil.defaultIfNull(attr, UploadFileAttributeDTO::new);
            attr
                    .setOriginalFilename(file.getOriginalFilename())
                    .setContentType(file.getContentType())
                    .setMd5(md5)
                    // 手动覆盖前端传参
                    .setPlatform(null)
                    .setUseOriginalFilenameAsDownloadFileName(false);
            bo = ossUploadDownloadFacade.upload(file.getBytes(), attr);
        }
        return ApiResult.data(this.toUploadResult(bo, request.getRequestURL().toString(), file.getOriginalFilename()));

    }
    /**
     * 将 OssFileInfoBO 转换为 OssFileUploadResultVO
     */
    private OssFileUploadResultVO toUploadResult(OssFileInfoBO ossFileInfo, String requestUrl, String originalFilename) {
        OssFileUploadResultVO ret = new OssFileUploadResultVO()
                .setFileId(ossFileInfo.getId())
                .setFilename(ossFileInfo.getStorageFilenameFull())
                // 返回本次上传文件的原始文件名
                .setOriginalFilename(originalFilename);

        /*
        这里请根据实际业务性质调整
        有的业务出于安全目的，不能暴露直链，只能通过服务端代理下载后，返回 byte[]
        有的业务没有限制，上传后文件完全可以直接通过对象存储直链下载，如此还能节约服务端上传带宽
        有的业务有安全要求，只能通过预签名地址下载
        但本地存储又没有直链，只能通过文件ID；
        默认地，此处按【本地存储or对象存储直链为空：通过文件ID下载；对象存储：通过对象存储直链下载】返回 url
         */
        if (
                ossUploadDownloadFacade.isLocalPlatform(ossFileInfo.getStoragePlatform())
                        || CharSequenceUtil.isEmpty(ossFileInfo.getDirectUrl())
        ) {
            ret.setUrl(
                    // 默认接口风格为 RESTful，下载即为最后拼接“/{文件ID}”
                    String.format("%s/%s", requestUrl, ossFileInfo.getId())
            );
        } else {
            // 获取预签名地址可参考 OssUploadDownloadFacadeImpl 的 downloadById 方法
            ret.setUrl(ossFileInfo.getDirectUrl());
        }

        return ret;
    }
}
